package gee

import (
	"encoding/json"
	"fmt"
	"net/http"
)

// H 构建JSON数据时，显得更简洁
type H map[string]interface{}

// Context 请求上下文
type Context struct {
	Writer http.ResponseWriter // 响应
	Req    *http.Request       // 请求

	Path   string            // 请求路径
	Method string            // 请求方法
	Params map[string]string // 路由解析后的参数

	StatusCode int // 状态码

	// middleware
	handlers []HandlerFunc
	index    int // 记录当前执行到第几个中间件

	engine *Engine // 引擎
}

// newContext 获取上下文实例
func newContext(w http.ResponseWriter, req *http.Request) *Context {
	return &Context{
		Writer: w,
		Req:    req,
		Path:   req.URL.Path,
		Method: req.Method,
		index:  -1,
	}
}

// PostForm 通过key获取表单参数
func (c *Context) PostForm(key string) string {
	return c.Req.FormValue(key)
}

// Query 通过key获取query的参数
func (c *Context) Query(key string) string {
	return c.Req.URL.Query().Get(key)
}

// Status 设置响应状态码
func (c *Context) Status(code int) {
	c.StatusCode = code
	c.Writer.WriteHeader(code)
}

// SetHeader 设置响应头
func (c *Context) SetHeader(key string, value string) {
	c.Writer.Header().Set(key, value)
}

// String 以字符串的形式整理响应数据
func (c *Context) String(code int, format string, values ...interface{}) {
	c.SetHeader("Content-Type", "text/plain")
	c.Status(code)
	c.Writer.Write([]byte(fmt.Sprintf(format, values...)))
}

// JSON 以json的形式整理响应数据
func (c *Context) JSON(code int, obj interface{}) {
	c.SetHeader("Content-Type", "application/json")
	c.Status(code)
	encoder := json.NewEncoder(c.Writer)
	if err := encoder.Encode(obj); err != nil {
		http.Error(c.Writer, err.Error(), 500)
	}
}

// Data 字节切片的形式响应数据
func (c *Context) Data(code int, data []byte) {
	c.Status(code)
	c.Writer.Write(data)
}

// HTML 以HTML格式响应数据
func (c *Context) HTML(code int, name string, data interface{}) {
	c.SetHeader("Content-Type", "text/html")
	c.Status(code)
	// 模板输出
	if err := c.engine.htmlTemplates.ExecuteTemplate(c.Writer, name + ".html", data); err != nil {
		c.String(http.StatusInternalServerError, err.Error())
	}
}

// Param 获取路由配置key对应的值
func (c *Context) Param(key string) string {
	value, _ := c.Params[key]
	return value
}

// Next 继续处理请求
func (c *Context) Next() {
	c.index++            // 依次添加中间件次序
	s := len(c.handlers) // 总的中间件的数量
	for ; c.index < s; c.index++ {
		c.handlers[c.index](c) // 依次进行中间件处理
	}
}
